(function () {

    /** 
     * @private
     * @constructor 
     */
    function YTPlaceholder (video_id, width, height, container, params) {
        this.video_id = video_id;
        this.width = width;
        this.height = height;
        this.container = container;
        this.params = params;
    }

    function meetsRequirements () {
        return !!(document.querySelectorAll && window.postMessage);
    }
    
    var objects = [];
    
    /**
     * @returns {Object}
     */
    function splitParams(query) {
        query = query.replace('&amp;', '&')
        var param_parts = query.split('&');
        var i;
        var param;
        var params = {};
        for (i=0; i < param_parts.length; i++) {
            param = param_parts[i].split('=')
            if (param.length == 2) {
                params[param[0]] = param[1];
            }
        }
        return params;
    }
    
    /**
     * Grab the current youtube objects
     */
    function grabElements() {
        var objs = document.querySelectorAll('object'),
            ob,
            i;
        var yt_re = /http:\/\/www.youtube.com\/v\/([0-9a-zA-Z\_\-]+)/;
        var matched;
        var src;
        for (i=0; i < objs.length; i++) {
            ob = objs[i];
            /**
             * A few wordpress plugins like to store the url here,
             * which is fast for us
             */
            if (ob.data && (matched = ob.data.match(yt_re))) {
                src = ob.data;
            } else {
                /**
                 * Standard embed <param> lookup
                 */
                var child = ob.firstChild;
                while (child) {
                    if (child.name == 'movie' && 
                        child.value && (matched = child.value.match(yt_re))) {
                        src = child.value;
                        break;
                    }
                    child = child.nextSibling;
                }
            }
            if (src) {
                // we have a youtube object
                var parts = src.split('?', 2);
                    
                if (parts.length > 1) {
                    src = parts[1];
                }
                
                var params = splitParams(src),
                    width = ob.width + '',
                    height = ob.height + '',
                    video_id = matched[1],
                    container = document.createElement('span');
                if (width.charAt(width.length-1) != '%') {
                    width = width + 'px';
                }
                if (height.charAt(height.length-1) != '%') {
                    height = height + 'px';
                }
                // Try to fill up the same space
                container.style.width = width;
                container.style.height = height;
                
                // replace the parent;
                ob.parentNode.replaceChild(container, ob);
                
                objects.push(new YTPlaceholder (video_id, 
                                                width, 
                                                height, 
                                                container, 
                                                params));
            }
        }
        // try to force loss of references to objects
        delete objs;
    }
    
    /**
     * Actually insert the elements here
     */
    function processElements() {
        var i, placeholder;
        for (i=0; i < objects.length; i++) {
            placeholder = objects[i];
            var player = new YT.Player(placeholder.container, {
                    "height": placeholder.height,
                    "width": placeholder.width,
                    "videoId": placeholder.video_id,
                    "playerVars": placeholder.params
                });
        }
    }
    
    /**
     * @param {function()=} existing
     * @returns {function()}
     */
    function createAPIReady (existing) {
        return function () {
            processElements();
            if (existing) {
                existing();
            }
        }
    }
    
    /**
     * Main entry point
     */
    function insertYTAPI () {
        grabElements();
        if (window['YT'] && YT.Player) {
            (createAPIReady())();
        } else {
            window['onYouTubePlayerAPIReady'] = createAPIReady(window['onYouTubePlayerAPIReady']);
            var tag = document.createElement('script');
            tag.src = 'http://www.youtube.com/player_api';
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
        }
    }
    
    /**
     * Off we go
     */
    if (meetsRequirements()) {
        insertYTAPI();
    }
})();
